package com.tjec.project.system.controller;

import com.tjec.common.enums.ErrCode;
import com.tjec.common.utils.SFtpUtil;
import com.tjec.common.utils.StringUtils;
import com.tjec.framework.aspectj.lang.annotation.Log;
import com.tjec.framework.aspectj.lang.enums.BusinessType;
import com.tjec.framework.web.domain.AjaxResult;
import com.tjec.project.system.domain.vo.BmsAttachmentVo;
import com.tjec.project.system.service.IBmsAttachmentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件下载Controller
 *
 * @author liuxu
 * @date 2020-04-27
 */
@Api(value = "文件下载Controller", tags = { "文件下载接口" })
@RestController
@RequestMapping("/api/system/download")
public class DownloadController {
	private static final Logger log = LoggerFactory.getLogger(DownloadController.class);
	
	@Value("${tjec.profile}")
	private String profile;
	//@Value("${tjec.profileNew}")
	//private String profileNew;
	@Autowired
	private IBmsAttachmentService iBmsAttachmentService;
	@Autowired
	private SFtpUtil sftp;

	/**
	 * 获取文件下载路径
	 */
	@ApiOperation("获取文件下载路径，可批量获取")
	@ApiImplicitParam(name = "guids", value = "文件guids", required = true, dataType = "String", paramType = "query")
	@PreAuthorize("@ss.hasPermi('system:download:getFiles')")
	@Log(title = "获取文件下载路径", businessType = BusinessType.OTHER)
	@GetMapping("/getFiles")
	public AjaxResult getFiles(String guids) {
		if (StringUtils.isBlank(guids)) {
			return new AjaxResult(ErrCode.SYS_PARAMETER_EMPTY.getErrCode(), ErrCode.SYS_PARAMETER_EMPTY.getErrMsg());
		}
		return AjaxResult.success(iBmsAttachmentService.selectBmsAttachmentDownload(guids));
	}

	@ApiOperation("用于断点下载文件,Range放head，如：bytes=3000-6000")
	@ApiImplicitParam(name = "guid", value = "文件guid", required = true, dataType = "String", paramType = "query")
	@GetMapping("/{guid}")
	public AjaxResult getDownload(@PathVariable String guid, HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// Get your file stream from wherever.
		log.info("guid=" + guid);
		List<BmsAttachmentVo> list = iBmsAttachmentService.selectBmsAttachmentDownloadabsolute(guid);
		if (CollectionUtils.isEmpty(list)) {
			return AjaxResult.error("数据库不存在该文件记录");
		}
		// String fullPath = ResourceUtils.getURL("classpath:").getPath() +
		// "static/1.jpg";
		String fullPath = profile + list.get(0).getStoragePath();
		File downloadFile = new File(fullPath);
		long downloadSize = downloadFile.length();
		if (downloadSize == 0) {
			sftp.connectServer();
			String storagePath = list.get(0).getStoragePath();
			String path = storagePath.substring(0, storagePath.lastIndexOf("/") + 1);
			//File file = new File(profile + path);
			File file = new File(profile + path);
			file.mkdirs();
			sftp.download(profile + path, list.get(0).getFileName(), profile+list.get(0).getStoragePath());
			//sftp.download(profile + path, list.get(0).getFileName(), fullPath);
			downloadFile = new File(fullPath);
			downloadSize = downloadFile.length();
		}
		log.info("下载路径:" + fullPath);

		RandomAccessFile in = null;
		try {
			in = new RandomAccessFile(downloadFile, "rw");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return AjaxResult.error("服务器不存在该文件");
		}

		ServletContext context = request.getServletContext();
		// get MIME type of the file
		String mimeType = context.getMimeType(fullPath);
		if (mimeType == null) {
			// set to binary type if MIME mapping not found
			mimeType = "application/octet-stream";
		}

		// set content attributes for the response
		response.setContentType(mimeType);
		// response.setContentLength((int) downloadFile.length());

		// set headers for the response
		String headerKey = "Content-Disposition";
		String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getName());
		response.setHeader(headerKey, headerValue);
		// 解析断点续传相关信息
		response.setHeader("Accept-Ranges", "bytes");

		long fromPos = 0, toPos = 0;
		if (request.getHeader("Range") == null) {
			response.setHeader("Content-Length", downloadSize + "");
		} else {
			// 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
			response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
			String range = request.getHeader("Range");
			String bytes = range.replaceAll("bytes=", "");
			String[] ary = bytes.split("-");
			fromPos = Long.parseLong(ary[0]);
			if (ary.length == 2) {
				toPos = Long.parseLong(ary[1]);
			}
			int size;
			// bytes=200-400
			if (toPos > fromPos) {
				size = (int) (toPos - fromPos);
			} else {
				size = (int) (downloadSize - fromPos);
			}
			response.setHeader("Content-Length", size + "");
			downloadSize = size;
		}

//        // Copy the stream to the response's output stream.

		try (OutputStream out = response.getOutputStream()) {

			// 设置下载起始位置
			if (fromPos > 0) {
				in.seek(fromPos);
			}
			// 缓冲区大小
			int bufLen = (int) (downloadSize < 2048 ? downloadSize : 2048);
			byte[] buffer = new byte[bufLen];
			int num;
			int count = 0; // 当前写到客户端的大小

			while ((num = in.read(buffer)) != 0) {
				out.write(buffer, 0, num);
				count += num;
				// 处理最后一段，计算不满缓冲区的大小
				if (downloadSize - count < bufLen) {
					bufLen = (int) (downloadSize - count);
					if (bufLen == 0) {
						break;
					}
					buffer = new byte[bufLen];
				}
			}
			response.flushBuffer();

		} catch (IOException e) {
			log.info("数据被暂停或中断。");
			e.printStackTrace();
		} finally {

			if (null != in) {
				try {
					in.close();
					return null;
				} catch (IOException e) {
					log.info("数据被暂停或中断。");
					// e.printStackTrace();
				}
			}
		}
		return AjaxResult.error("fileName", list.get(0).getFileName());
	}

	@PostMapping("/getZip")
	public void downloadZip(@RequestBody String[] guids, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		if (guids == null || guids.length == 0) {
			log.info("未选择下载的文件！");
			// return AjaxResult.error(100, "未选择下载的文件！");
		} else {

			List<BmsAttachmentVo> list = iBmsAttachmentService.selectBmsAttachmentDownload(guids);
			if (list == null || list.size() == 0) {

			} else {
				response.setContentType("application/octet-stream");
				response.setHeader("Content-Disposition", "attachment; filename=tjec.zip");
				ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());

				// key="文件名" value="文件地址"
				Map<String, String> fileMap = new HashMap<>();
				List<String> fileNames = new ArrayList<String>();
				if (list != null && list.size() > 0) {
					list.forEach(item -> {
						String fileName = item.getFileName();
						
						String newFileName = checkFileName(fileNames,fileName,1);
						fileNames.add(newFileName);
						item.setFileName(newFileName);
						/*if (fileNames.size() > 0) {
							
							String newFileName = checkFileName(fileNames,fileName,1);
							fileNames.add(newFileName);
							item.setFileName(newFileName);
							if (fileNames.contains(fileName)) {
								String newFileName = fileName.substring(0, lastIndex) + "(1)"
										+ fileName.substring(lastIndex);
								fileNames.add(newFileName);
								item.setFileName(newFileName);
							} else {
								fileNames.add(fileName);
							}
						} else {
							fileNames.add(fileName);
						}*/

						// fileMap.put(item.getFileName(),
						// "http://10.66.37.181/profile"+item.getStoragePath());
						// fileMap.put(item.getFileName(), profile+item.getStoragePath());
						fileMap.put(item.getFileName(),item.getStoragePath());

					});
					Map<String, RandomAccessFile> isMap = getStringInputStreamMap(fileMap);
					isMap.forEach((fileName, is) -> {
						addToZip(is, zipOut, fileName);
					});
				}

				zipOut.flush();
				zipOut.close();
				// return AjaxResult.success();
			}

		}

	}
	
	/**
	 * 
	 * @param names 文件下文件名的集合
	 * @param name 存入的文件名
	 * @param index 索引的开始位置
	 * @return 符合要求的文件名
	 */
	private static String checkFileName(List<String> names,String name,int index) {
		int lastIndex = name.lastIndexOf('.');
		if(names.contains(name)) {
			if(index>1 && name.lastIndexOf("("+(index-1)+")")>-1) {
				int newIndex = name.lastIndexOf("("+(index-1)+")");
				String newName = name.substring(0, newIndex)+"("+index+")"+name.substring(name.lastIndexOf("."));
				name = checkFileName(names,newName,index+1);
			}else {
				name = checkFileName(names,name.substring(0, lastIndex)+"("+index+")"+name.substring(name.lastIndexOf(".")),index+1);
			}
		} else {
			return name;
		}
		return name;
	}
	
	/* 处理文件 */
	private Map<String, RandomAccessFile> getStringInputStreamMap(Map<String, String> pictureMap) {
		Map<String, RandomAccessFile> isMap = new HashMap<String, RandomAccessFile>();
		for (Map.Entry<String, String> entry : pictureMap.entrySet()) {
			String fileName = entry.getKey();
			try {
				sftp.connectServer();
				String storagePath = entry.getValue();
				String path = storagePath.substring(0, storagePath.lastIndexOf("/") + 1);
				File file = new File(profile + path);
				//File file = new File("\\home\\tjec\\new");
				boolean res = file.mkdirs();
				log.info("创建文件夹结果："+res);
				sftp.download(profile + path, fileName, profile+storagePath);
				File downloadFile = new File(profile+storagePath);
				RandomAccessFile in = new RandomAccessFile(downloadFile, "rw");
				isMap.put(fileName, in);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return isMap;
	}

	/* 添加压缩文件 */
	private void addToZip(RandomAccessFile is, ZipOutputStream zipOut, String fileName) {
		try {
			ZipEntry entry = new ZipEntry(fileName);
			zipOut.putNextEntry(entry);
			int len;
			byte[] buffer = new byte[1024];
			while ((len = is.read(buffer)) > 0) {
				zipOut.write(buffer, 0, len);
			}
			zipOut.closeEntry();
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/* 处理文件 */
	/*private Map<String, InputStream> getStringInputStreamMap(Map<String, String> pictureMap) {
		Map<String, InputStream> isMap = new HashMap<String, InputStream>();
		for (Map.Entry<String, String> entry : pictureMap.entrySet()) {
			String fileName = entry.getKey();
			try {
				URL url = new URL(entry.getValue());
				URLConnection con = url.openConnection();
				// 设置超时间为3秒
				con.setConnectTimeout(3 * 1000);
				// 防止屏蔽程序抓取而返回403错误
				con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
				InputStream is = con.getInputStream();
				isMap.put(fileName, is);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return isMap;
	}*/

	/* 添加压缩文件 */
	/*private void addToZip(InputStream is, ZipOutputStream zipOut, String fileName) {
		try {
			ZipEntry entry = new ZipEntry(fileName);
			zipOut.putNextEntry(entry);
			int len;
			byte[] buffer = new byte[1024];
			while ((len = is.read(buffer)) > 0) {
				zipOut.write(buffer, 0, len);
			}
			zipOut.closeEntry();
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}*/
}
